package top.starmc.starpet.internal

import eos.moe.dragoncore.network.PacketSender
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import taboolib.common.platform.function.getDataFolder
import taboolib.common.platform.function.submit
import taboolib.module.nms.itemTagReader
import taboolib.platform.util.isNotAir
import taboolib.platform.util.sendLang
import top.starmc.starpet.config.Config
import top.starmc.starpet.entity.EntityPet
import top.starmc.starpet.util.*
import java.io.File

class PlayerData(val owner: Player) {
    lateinit var file: File

    var item: ItemStack? = null

    var internal: PetData? = null

    var entity: EntityPet? = null

    var experience = 0

    var level = 0

    private val timeMap = hashMapOf<String, Long>()

    init {
        val yaml = YamlConfiguration()
        if (Config.useSQL()) {
            Config.mysql.getData(owner)?.let {
                yaml.loadFromString(it)
            }
        } else {
            file = File(getDataFolder(), "PlayerData/${owner.uniqueId}.yml")
            if (file.isFile) {
                yaml.load(file)
            }
        }
        yaml.getItemStack("item")?.let {
            setPet(it)
        }
    }

    fun setPet(target: ItemStack) {
        item = target
        if (target.isPetItem()) {
            target.itemTagReader {
                internal = Config.internalMap[getString("宠物")]
                experience = getInt("经验")!!
                level = getInt("等级")!!
                updateStats()
                removeEntity()
                spawnEntity()
            }
        } else {
            internal = null
            experience = 0
            level = 0
            owner.removeStats(PlayerData::class.java)
            owner.removeStats(SkillData::class.java)
            removeEntity()
        }
        PacketSender.putClientSlotItem(owner, Config.equipSlot, item)
    }

    fun spawnEntity() {
        entity = EntityPet(owner, this, owner.location).also {
            PacketSender.sendSyncPlaceholder(owner, mapOf(Pair("StarPet_Pet_UUID", it.uniqueID.toString())))
        }
    }

    fun removeEntity() {
        entity?.die()
        entity = null
    }

    fun callPet() {
        if (entity != null) {
            removeEntity()
        } else {
            spawnEntity()
        }
    }

    fun addExp(number: Int) {
        if (level >= internal!!.maxLevel) {
            return
        }
        var amount = number
        var maxExp = getMaxExp()
        var levelUp = false
        while (amount > 0) {
            if (maxExp == -1) {
                break
            }
            if (experience + amount >= maxExp) {
                amount = (experience + amount) - maxExp
                experience = 0
                level++
                maxExp = getMaxExp()
                levelUp = true
            } else {
                experience += amount
                break
            }
        }
        if (levelUp) {
            owner.sendLang("1", level)
            entity?.customName = getLevelName()
            updateStats()
        } else {
            owner.sendLang("0", number)
        }
        item!!.updatePetData(internal!!, experience, level)
    }

    private fun updateStats() {
        owner.updateStats(
            PlayerData::class.java,
            internal!!.levelStats.entries.filter { level >= it.key }.flatMap { it.value.calculate("<:", ":>", level) })
    }

    fun getMaxExp(): Int {
        return internal!!.getMaxExp(level)
    }

    fun getLevelName(): String {
        return internal!!.levelNameMap.floorEntry(level).value ?: "无名字"
    }

    fun runSkill(type: String, keys: List<String>? = null) {
        internal!!.skillMap[type]?.forEach {
            it.runSkill(this, keys)
        }
    }

    fun updateSkillStats(skill: SkillData) {
        val tempList = mutableListOf<String>()
        skill.stats.forEach {
            val args = it.split(";")
            val line = args[0].calculate(level)
            submit(delay = args[1].calculate(level).toLong() * 20L) {
                tempList -= line
                owner.updateStats(SkillData::class.java, tempList)
            }
        }
        owner.updateStats(SkillData::class.java, tempList)
    }

    fun getCoolDown(key: String, limit: Long): Long {
        if (key !in timeMap) {
            return -1
        }
        val time = (System.currentTimeMillis() - timeMap[key]!!) / 1000
        return if (time <= limit) limit - time else -1
    }

    fun addCoolDown(key: String) {
        timeMap[key] = System.currentTimeMillis()
    }

    fun saveData() {
        removeEntity()
        val yaml = YamlConfiguration()
        if (item.isNotAir()) {
            yaml["item"] = item
        }
        if (Config.useSQL()) {
            Config.mysql.saveData(owner, yaml.saveToString())
        } else {
            yaml.save(file)
        }
    }
}